<template>
  <div>
    <!-- 决策树 -->
    <div class="decision-tree" :style="{ width: `${max_width}px` }">
      <div
        v-for="(a, row) in tree_depth"
        :key="`row${row}`"
        :style="{
          position: 'absolute',
          top: `${row * (space_y + leaf_height) + space_y / 2}px`,
          width: `${max_width}px`,
          height: `${leaf_height}px`,
        }"
      >
        <div v-for="(b, col) in pow(row, 2)" :key="`row${row}-col${col}`">
          <div
            v-show="tree_data[row][col] !== -1"
            class="leaf"
            :style="getLeafPosition(row, col)"
          >
            <div
              v-if="row === 1"
              style="margin-top: -20px; padding: 0 20%;"
              :align="col % 2 === 0 ? 'left' : 'right'"
            >
              {{ col % 2 === 0 ? 'True' : 'False' }}
            </div>
            <p>{{ getLeafContent(row, col)[0] }}</p>
            <p>{{ getLeafContent(row, col)[1] }}</p>
            <p
              v-if="tree_structure.is_leaves[tree_data[row][col]]"
              :style="{ 'line-height': `${leaf_height}px` }"
            >
              {{ tree_structure.classes[tree_data[row][col]] }}
            </p>
          </div>
        </div>
      </div>
      <!-- 连接线 -->
      <line-of-relational-connection
        v-for="(edge, index) in getEdgeInfo()"
        :key="`edge${index}`"
        :edge="edge"
        :node-height="leaf_height"
        :node-width="leaf_width"
        :difference-of-grid-width="0"
        :difference-of-grid-height="0"
      />
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
// 连线
import LineOfRelationalConnection from '@/components/studio/data/model/Line.vue'
import { toInteger } from 'lodash'
import DataViewStore from '@/store/modules/dataview'

@Component({
  components: { LineOfRelationalConnection },
})
export default class DrawDecisionTree extends Vue {
  // tree
  public node_number: number = 0
  public tree_depth: number = 0
  public tree_structure: any = {}
  public leaf_width: number = 100
  public max_width: number = 0
  public max_height: number = 0
  public leaf_height: number = 44
  public space_x: number = 10
  public space_y: number = 40
  public tree_data: any = []
  public circelArray: any = []
  public fullScreenVisivle: boolean = false

  public get modelData() {
    return DataViewStore.selectModel
  }

  public created() {
    this.init()
  }

  public init() {
    this.drawTree()
  }

  public drawTree() {
    this.tree_structure = this.modelData?.data?.tree_structure
    this.tree_depth = this.tree_structure?.max_depth
    this.node_number = this.tree_structure?.n_nodes
    this.max_width =
      this.leaf_width * this.pow(this.tree_depth - 1, 2) +
      this.space_x * this.pow(this.tree_depth - 1, 2)
    this.max_height =
      this.leaf_height * this.tree_depth +
      this.space_x * (this.tree_depth - 1) +
      this.space_y / 2

    const tree: any = []
    for (let i = 0; i < this.tree_depth; i += 1) {
      const floor = new Array(this.pow(i, 2))
      tree.push(floor)
    }
    tree[0][0] = 0
    const nodes = this.tree_structure.node_depth
    const left = this.tree_structure.children_left
    const right = this.tree_structure.children_right
    nodes.forEach((element: any, row: any) => {
      if (row < this.tree_depth - 1) {
        for (let col = 0; col < this.pow(row, 2); col += 1) {
          tree[row + 1][col * 2] =
            tree[row][col] !== -1 ? left[tree[row][col]] : -1
          tree[row + 1][col * 2 + 1] =
            tree[row][col] !== -1 ? right[tree[row][col]] : -1
        }
      }
    })
    this.tree_data = tree
  }

  public getLeafPosition(row: number, col: number) {
    const left =
      (this.max_width / this.pow(row, 2)) * col +
      this.max_width / this.pow(row + 1, 2) -
      this.leaf_width / 2
    const top = 0 // this.space_y*row
    return {
      left: `${left}px`,
      top: `${top}px`,
      // background: `${this.rgbColor()}`,
    }
  }

  public getStartEndPos(row: number, col: number) {
    return Number(this.getLeafPosition(row, col).left.replace(/px/, ''))
  }

  public getEdgeInfo() {
    const edgeInfo: any = []
    for (let row = 0; row < this.tree_depth - 1; row += 1) {
      for (let col = 0; col <= this.pow(row + 1, 2) - 1; col += 1) {
        if (this.tree_data[row + 1][col] === -1) {
          edgeInfo.push(false)
        } else {
          const left = col % 2 === 0
          const item = {
            x:
              (left
                ? this.max_width / this.pow(row + 2, 2) - this.leaf_width / 2
                : this.max_width / this.pow(row + 1, 2)) +
              (toInteger(col / 2) * this.max_width) / this.pow(row, 2),
            y:
              this.leaf_height * (row + 1) +
              this.space_y / 2 +
              row * this.space_y,
            startEndPos: {
              xStart: left
                ? this.max_width / this.pow(row + 2, 2) + this.leaf_width / 2
                : 0,
              yStart: 0,
              xEnd: !left
                ? this.max_width / this.pow(row + 2, 2) + this.leaf_width / 2
                : 0,
              yEnd: this.space_y,
            },
            isLeft: left,
          }
          edgeInfo.push(item)
        }
      }
    }
    return edgeInfo
  }

  public getLeafContent(row: any, col: any) {
    const feature = this.tree_structure.feature[this.tree_data[row][col]]
    const threshold = this.tree_structure.threshold[this.tree_data[row][col]]
    if (feature > -2) {
      if (threshold > -2) {
        return [this.modelData.data?.feature_list[feature], `<=${threshold}`]
      }
    }
    return ''
  }

  public pow(n: number, x: number) {
    if (n > 0) {
      for (let i = n; i > 1; i -= 1) {
        x *= 2
      }
      return x
    }
    return 1
  }
}
</script>

<style lang="less" scoped>
@import '@/styles/scroll-bar';

.decision-tree {
  min-height: 100px;
  position: relative;

  .leaf {
    border: 1px solid #d3d9e6;
    border-radius: 4px;
    height: 44px;
    position: absolute;
    text-align: center;
    width: 100px;

    p {
      margin: 0;
    }
  }
}
</style>
